﻿using System.Collections.Generic;
using System.Runtime.InteropServices;

namespace DimsMapper
{
    public static class Object
    {
        public enum Types : int
        {
            Item,
            Critter,
            Scenery,
            Walls,
            Tiles,
            Misc,
            Interface,
            Inventory,
        }

        public enum Slot : int
        {
            None = 0,
            Left = 1,
            Right = 2,
            Worn = 3,
        }

        public class ObjectInventoryItems
        {
            public int count;
            public GameObject item;

            public ObjectInventoryItems() {}

            public ObjectInventoryItems(GameObject item)
            {
                this.item = item;
                count = 1;
            }

            public void SetCount(int newCount)
            {
                count = newCount;
            }
        }

        public struct ObjectInventory
        {
            public int count;
            public int capacity;
            public List<ObjectInventoryItems> items;
        }

        public struct ObjectCritter
        {
            public int damageLastTurn;
            public int maneuver;
            public int ap;
            public int damageResults;
            public int aiPacket;
            public int team;
            public int whoHitMeCid;

            public int hp;
            public int radiation;
            public int poison;
        }

        public struct ObjectItemWeaponData
        {
            public int ammoQuantity;
            public int ammoTypePid;
            public int unused_2;
            public int unused_3;
            public int unused_4;
            public int unused_5;
            public int unused_6;
            public int unused_7;
            public int unused_8;
            public int unused_9;
        }

        public struct ObjectItemAmmoData
        {
            public int quantity;
            public int unused_1;
            public int unused_2;
            public int unused_3;
            public int unused_4;
            public int unused_5;
            public int unused_6;
            public int unused_7;
            public int unused_8;
            public int unused_9;
        } 

        public struct ObjectItemMiscData
        {
            public int charges;
            public int unused_1;
            public int unused_2;
            public int unused_3;
            public int unused_4;
            public int unused_5;
            public int unused_6;
            public int unused_7;
            public int unused_8;
            public int unused_9;
        }

        public struct ObjectItemKeyData
        {
            public int code;
            public int unused_1;
            public int unused_2;
            public int unused_3;
            public int unused_4;
            public int unused_5;
            public int unused_6;
            public int unused_7;
            public int unused_8;
            public int unused_9;
        }

        [StructLayout(LayoutKind.Explicit, Pack = 1)]
        public struct ObjectItem
        {
            [FieldOffset(0)] public ObjectItemWeaponData weapon;
            [FieldOffset(0)] public ObjectItemAmmoData ammo;
            [FieldOffset(0)] public ObjectItemMiscData misc;
            [FieldOffset(0)] public ObjectItemKeyData key;
        }

        public struct ObjectSceneryDoorData
        {
            public int openFlags;
            public int unused_1;
            public int unused_2;
            public int unused_3;
            public int unused_4;
            public int unused_5;
            public int unused_6;
            public int unused_7;
            public int unused_8;
            public int unused_9;
        }

        public struct ObjectSceneryStairsData
        {
            public int destinationMap;
            public int destinationBuiltTile;
            public int unused_2;
            public int unused_3;
            public int unused_4;
            public int unused_5;
            public int unused_6;
            public int unused_7;
            public int unused_8;
            public int unused_9;
        }

        public struct ObjectSceneryElevatorData
        {
            public int elevatorTypeID;
            public int elevatorLevel;
            public int unused_2;
            public int unused_3;
            public int unused_4;
            public int unused_5;
            public int unused_6;
            public int unused_7;
            public int unused_8;
            public int unused_9;
        }

        [StructLayout(LayoutKind.Explicit, Pack = 1)]
        public struct ObjectScenery
        {
            [FieldOffset(0)] public ObjectSceneryDoorData door;
            [FieldOffset(0)] public ObjectSceneryElevatorData elevator;
            [FieldOffset(0)] public ObjectSceneryStairsData stairs;
            [FieldOffset(0)] public ObjectSceneryStairsData ladder;
        }
        
        public struct ObjectMisc
        {
            public int map;
            public int tile;
            public int elevation;
            public int rotation;
            public int unused_4;
            public int unused_5;
            public int unused_6;
            public int unused_7;
            public int unused_8;
            public int unused_9;
        }

        public struct ObjectWalls
        {
            public int unused_0;
            public int unused_1;
            public int unused_2;
            public int unused_3;
            public int unused_4;
            public int unused_5;
            public int unused_6;
            public int unused_7;
            public int unused_8;
            public int unused_9;
        }

        [StructLayout(LayoutKind.Explicit, Pack = 1)]
        public struct ObjectData
        {
            [FieldOffset(0)] public int update_flags;

            // обьединения
            [FieldOffset(4)] public ObjectCritter critter;
            [FieldOffset(4)] public ObjectItem item;
            [FieldOffset(4)] public ObjectScenery scenery;
            [FieldOffset(4)] public ObjectMisc misc;
            [FieldOffset(4)] public ObjectWalls walls;
        }

        public class GameObject
        {
            public int id;
            public int tile;
            public int x;
            public int y;
            public int sx;
            public int sy;
            public int frame;
            public int rotation;
            public int fid;
            public int flags;
            public int elevation;

            public ObjectInventory inventory;
            public ObjectData data; // это занимает 11 полей

            public int pid;
            public int cid;
            public int lightDistance;
            public int lightIntensity;
            public int outline;
            public int sid;
            public GameObject owner;
            public int scriptIndex;


            internal bool selected;

            public void SetHex(int x, int y)
            {
                tile = y * 200 + x;
            }

            public void GetHexXY(out int x, out int y)
            {
               x = tile % 200;
               y = tile / 200;
            }

            public Types GetFidType()
            {
                return (Types)((fid & 0x0F000000) >> 24);
            }

            public Types GetPidType()
            {
                return (Types)(pid >> 24);
            }

            public Slot GetSlot()
            {
                if ((flags & 0x02000000) != 0) return Slot.Right;
                if ((flags & 0x01000000) != 0) return Slot.Left;
                return ((flags & 0x04000000) != 0) ? Slot.Worn : Slot.None;
            }

            public bool IsFlat()
            {
                return (flags & 0x00000008) != 0;
            }

            public bool IsItem()
            {
                return GetPidType() == Types.Item;
            }

            public override string ToString()
            {
                return "Tile: " + tile.ToString() + " PID: " + pid.ToString();
            }
        }
    }
}
